﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HybridLab.Workflow.Activities.UI
{
	internal partial class DeploymentPage : UserControl
	{
		private HybridLabWizardData wizardData;
		private int newRowIndex;
		private ErrorControl scriptErrorControl;

		public DeploymentPage()
		{
			newRowIndex = -1;
			InitializeComponent();
		}

		internal DeploymentPage(HybridLabWizardData wizardData)
			: this()
		{
			if (wizardData == null)
			{
				throw new ArgumentNullException("wizardData");
			}
			deploymentGroupBox.Enabled = false;
			this.wizardData = wizardData;
			this.wizardData.DataLoadCompleted += new EventHandler(wizardData_DataLoadCompleted);
			Load += new EventHandler(this.DeploymentScriptControl_Load);
		}

		private void addButton_Click(object sender, EventArgs e)
		{
			try
			{
				int rowIndex = 0;
				if (scriptsDataGridView.CurrentRow != null)
				{
					rowIndex = scriptsDataGridView.CurrentRow.Index + 1;
				}
				scriptsDataGridView.Rows.Insert(rowIndex, 1);
				scriptsDataGridView.CurrentCell = this.scriptsDataGridView.Rows[rowIndex].Cells[0];
				if (MachineColumn.Items.Count == 1)
				{
                    scriptsDataGridView.CurrentCell.Value = MachineColumn.Items[0];
					scriptsDataGridView.CurrentCell = scriptsDataGridView.Rows[rowIndex].Cells[1];
				}
				scriptsDataGridView.BeginEdit(true);
				newRowIndex = rowIndex;
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void AttachHandlers()
		{
			addButton.Click += new EventHandler(addButton_Click);
			deleteButton.Click += new EventHandler(deleteButton_Click);
			upButton.Click += new EventHandler(moveUpbutton_Click);
			downButton.Click += new EventHandler(downButton_Click);
			scriptsDataGridView.CurrentCellChanged += new EventHandler(scriptsDataGridView_CurrentCellChanged);
			scriptsDataGridView.Rows.CollectionChanged += new CollectionChangeEventHandler(Rows_CollectionChanged);
			deployCheckBox.CheckedChanged += new EventHandler(deployCheckBox_CheckedChanged);
			wizardData.DeploymentDetails.ErrorChanged += new EventHandler(DeploymentDetails_ErrorChanged);
			wizardData.EnvironmentDetails.EnvironmentChanged += new EventHandler(EnvironmentDetails_EnvironmentChanged);
			scriptsDataGridView.DataError += new DataGridViewDataErrorEventHandler(scriptsDataGridView_DataError);
			scriptsDataGridView.CellEndEdit += new DataGridViewCellEventHandler(scriptsDataGridView_CellEndEdit);
		}

		private void deleteButton_Click(object sender, EventArgs e)
		{
			newRowIndex = -1;
			try
			{
				int index = 0;
				if (scriptsDataGridView.CurrentRow != null)
				{
					index = this.scriptsDataGridView.CurrentRow.Index;
				}
				if (scriptsDataGridView.RowCount > 0)
				{
					scriptsDataGridView.Rows.RemoveAt(index);
				}
				if (scriptsDataGridView.RowCount > 0)
				{
					if (index == scriptsDataGridView.RowCount)
					{
						index = scriptsDataGridView.RowCount - 1;
					}
					scriptsDataGridView.CurrentCell = scriptsDataGridView.Rows[index].Cells[0];
				}
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void deployCheckBox_CheckedChanged(object sender, EventArgs e)
		{
			SetDeploymentNeededMode(deployCheckBox.Checked);
		}

		private void DeploymentDetails_ErrorChanged(object sender, EventArgs e)
		{
			RefreshErrors();
		}

		private void DeploymentScriptControl_Load(object sender, EventArgs e)
		{
			int width = scriptsDataGridView.Width;
            MachineColumn.Width = (int)Math.Floor((double)(0.25 * width));
			WorkingDirColumn.Width = (int)Math.Floor((double)(0.20 * width));
            ScriptColumn.Width = ((width - MachineColumn.Width) - WorkingDirColumn.Width) - 3;
		}

		private void downButton_Click(object sender, EventArgs e)
		{
			newRowIndex = -1;
			try
			{
				if (scriptsDataGridView.CurrentRow != null)
				{
					int index = scriptsDataGridView.CurrentRow.Index;
					int newIndex = index + 1;
					if (SwapRowValues(index, newIndex))
					{
						scriptsDataGridView.CurrentCell = scriptsDataGridView.Rows[newIndex].Cells[0];
						wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
					}
				}
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void EnvironmentDetails_EnvironmentChanged(object sender, EventArgs e)
		{
			if (wizardData.EnvironmentDetails.Environment != null)
            {
				InitializeMachineColumn();
                ValidateLabSystemColumn();
                wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
            }
		}

		private List<DeploymentScript> GetCurrentScripts()
		{
			List<DeploymentScript> list = new List<DeploymentScript>();
			for (int i = 0; i < this.scriptsDataGridView.RowCount; i++)
			{
				DeploymentScript item = new DeploymentScript();
				object agent = scriptsDataGridView.Rows[i].Cells[0].Value;
				item.Machine = (agent != null) ? agent.ToString() : null;
				agent = scriptsDataGridView.Rows[i].Cells[1].Value;
				item.Script = (agent != null) ? agent.ToString() : null;
				agent = scriptsDataGridView.Rows[i].Cells[2].Value;
				item.WorkingDirectory = (agent != null) ? agent.ToString() : null;
				list.Add(item);
			}
			return list;
		}

		private void Initialize()
		{
			try
			{
				deleteButton.Enabled = false;
				upButton.Enabled = false;
				downButton.Enabled = false;
				UpdateUI();
				InitializeErrorProviders();
				RefreshErrors();
				deleteButton.Enabled = scriptsDataGridView.RowCount > 0;
				AttachHandlers();
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void InitializeMachineColumn()
		{
            MachineColumn.Items.Clear();
			var lab = wizardData.EnvironmentDetails.Environment.GetLab(wizardData.Server);
			if (lab != null)
			{
				lab.LabSystems.ToList().ForEach(m => MachineColumn.Items.Add(m.ComputerName));
			}
		}

		private void InitializeErrorProviders()
		{
			scriptErrorControl = new ErrorControl();
			scriptErrorControl.Dock = DockStyle.Fill;
            pnlError.Controls.Add(scriptErrorControl);
		}

		private void wizardData_DataLoadCompleted(object sender, EventArgs e)
		{
			deploymentGroupBox.Enabled = true;
			Initialize();
		}

		private void moveUpbutton_Click(object sender, EventArgs e)
		{
			newRowIndex = -1;
			try
			{
				if (scriptsDataGridView.CurrentRow != null)
				{
					int index = scriptsDataGridView.CurrentRow.Index;
					int newIndex = index - 1;
					if (SwapRowValues(index, newIndex))
					{
						scriptsDataGridView.CurrentCell = scriptsDataGridView.Rows[newIndex].Cells[0];
						wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
					}
				}
			}
			catch (Exception exception)
			{
				OnError(exception);
			}
		}

		private void OnError(Exception ex)
		{
		}

		private void PopulateGrid(List<DeploymentScript> scripts)
		{
            InitializeMachineColumn();
			scriptsDataGridView.Rows.Clear();
			foreach (DeploymentScript script in scripts)
			{
				scriptsDataGridView.Rows.Add(script.Machine, script.Script, script.WorkingDirectory);
			}
			ValidateLabSystemColumn();
			wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
		}

        private void RefreshErrors()
        {
            scriptErrorControl.SetErrorMessage(wizardData.DeploymentDetails["Scripts"]);
        }

		private void ResetUI()
		{
			scriptsDataGridView.Rows.Clear();
		}

		private void Rows_CollectionChanged(object sender, CollectionChangeEventArgs e)
		{
			deleteButton.Enabled = this.scriptsDataGridView.RowCount > 0;
			wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
		}

		private void scriptsDataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
		{
			wizardData.DeploymentDetails.Scripts = GetCurrentScripts();
		}

		private void scriptsDataGridView_CurrentCellChanged(object sender, EventArgs e)
		{
			if (newRowIndex != -1)
			{
				if ((scriptsDataGridView.CurrentRow != null) && (scriptsDataGridView.CurrentRow.Index == newRowIndex))
				{
					scriptsDataGridView.BeginEdit(true);
				}
				else
				{
					newRowIndex = -1;
				}
			}
			if (scriptsDataGridView.CurrentRow != null)
			{
				upButton.Enabled = scriptsDataGridView.CurrentRow.Index != 0;
				downButton.Enabled = scriptsDataGridView.CurrentRow.Index < (scriptsDataGridView.RowCount - 1);
			}
		}

		private void scriptsDataGridView_DataError(object sender, DataGridViewDataErrorEventArgs e)
		{
		}

		private void SetDeploymentNeededMode(bool deploymentNeeded)
		{
			deployCheckBox.Checked = deploymentNeeded;
			wizardData.DeploymentDetails.DeploymentNeeded = deploymentNeeded;
            deploymentGroupBox.Enabled = deploymentNeeded;
			grpSnapshot.Visible = deploymentNeeded;
		}

		private bool SwapRowValues(int currentIndex, int newIndex)
		{
			int count = scriptsDataGridView.Rows.Count;
			if (currentIndex < 0 || currentIndex >= count || newIndex < 0 || newIndex >= count || currentIndex == newIndex)
			{
				return false;
			}
			for (int i = 0; i < scriptsDataGridView.ColumnCount; i++)
			{
				object obj2 = scriptsDataGridView.Rows[currentIndex].Cells[i].Value;
				scriptsDataGridView.Rows[currentIndex].Cells[i].Value = scriptsDataGridView.Rows[newIndex].Cells[i].Value;
				scriptsDataGridView.Rows[newIndex].Cells[i].Value = obj2;
			}
			return true;
		}

		private void UpdateUI()
		{
			var deploymentDetails = wizardData.DeploymentDetails;
			SetDeploymentNeededMode(deploymentDetails.DeploymentNeeded);
			PopulateGrid(deploymentDetails.Scripts);
			PopulateSnapshotInfo(deploymentDetails.TakePostDeploymentSnapshot, deploymentDetails.PostDeploymentSnapshotPrefix);
		}

		private void PopulateSnapshotInfo(bool doPostDeploySnapshot, string prefix)
		{
			chkPostDeploySnapshot.Checked = doPostDeploySnapshot;
			txtPrefix.Text = prefix;
		}

		private void ValidateLabSystemColumn()
		{
            var agents = new List<string>();
            foreach (var i in MachineColumn.Items)
            {
                agents.Add(i.ToString());
            }
            foreach(DataGridViewRow row in scriptsDataGridView.Rows)
            {
                if (!agents.Any(agent => row.Cells[0].Value != null && agent == row.Cells[0].Value.ToString()))
                {
                    row.Cells[0].Value = null;
                }
            }
		}

		private void chkPostDeploySnapshot_CheckedChanged(object sender, EventArgs e)
		{
			txtPrefix.Enabled = chkPostDeploySnapshot.Checked;
			wizardData.DeploymentDetails.TakePostDeploymentSnapshot = true;
		}

		private void txtPrefix_TextChanged(object sender, EventArgs e)
		{
			wizardData.DeploymentDetails.PostDeploymentSnapshotPrefix = txtPrefix.Text;
		}
	}
}
